package fun.huixi.weiju.config;

import fun.huixi.weiju.security.UserAuthenticationProvider;
import fun.huixi.weiju.security.UserPermissionEvaluator;
import fun.huixi.weiju.security.handler.*;
import fun.huixi.weiju.security.jwt.JwtAuthenticationTokenFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;

import javax.annotation.Resource;

/**
 * spring-security 配置类
 * @Author 叶秋
 * @Date 2020/1/19 13:23
 * @param
 * @return
 **/
@Configuration
@EnableWebSecurity
//开启权限注解,默认是关闭的
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    /**
     * 自定义登录成功处理器
     */
    @Resource
    private UserLoginSuccessHandler userLoginSuccessHandler;
    /**
     * 自定义登录失败处理器
     */
    @Resource
    private UserLoginFailureHandler userLoginFailureHandler;
    /**
     * 自定义注销成功处理器
     */
    @Resource
    private UserLogoutSuccessHandler userLogoutSuccessHandler;
    /**
     * 自定义暂无权限处理器
     */
    @Resource
    private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;
    /**
     * 自定义未登录的处理器
     */
    @Resource
    private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;
    /**
     * 自定义登录逻辑验证器
     */
    @Resource
    private UserAuthenticationProvider userAuthenticationProvider;


    /**
     * 加密方式
     * @Author Sans
     * @CreateTime 2019/10/1 14:00
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
    /**
     * 注入自定义PermissionEvaluator
     */
    @Bean
    public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler(){
        DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(new UserPermissionEvaluator());
        return handler;
    }





    /**
     * 密码登录配置
     * @Author 叶秋
     * @Date 2021/9/28 21:34
     * @param
     * @return
     **/
    @Configuration
    @Order(1)
    class UserPasswordLoginConfigurerAdapter extends WebSecurityConfigurerAdapter {

        /**
         * 配置登录验证逻辑
         */
        @Override
        protected void configure(AuthenticationManagerBuilder auth){
            //这里可启用我们自己的登陆验证逻辑
            auth.authenticationProvider(userAuthenticationProvider);
        }

        /**
         * 配置security的控制逻辑
         * @Author Sans
         * @CreateTime 2019/10/1 16:56
         * @Param  http 请求
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {

            http
                    // 不进行权限验证的请求或资源(从配置文件中读取)
                    .antMatcher("/login/userLogin")
                    // 配置未登录自定义处理类
                    .httpBasic().authenticationEntryPoint(userAuthenticationEntryPointHandler)
                    .and()
                    // 配置登录地址
                    .formLogin()
                    .loginProcessingUrl("/login/userLogin")
                    //登录表单form中用户名输入框input的name名，不修改的话默认是username, 我们只需要微信提供的code 就行
                    .usernameParameter("nickName")
                    // 配置登录成功自定义处理类
                    .successHandler(userLoginSuccessHandler)
                    // 配置登录失败自定义处理类
                    .failureHandler(userLoginFailureHandler)
                    .and()
                    // 配置登出地址
                    .logout()
                    .logoutUrl("/login/userLogout")
                    // 配置用户登出自定义处理类
                    .logoutSuccessHandler(userLogoutSuccessHandler)
                    .and()
                    // 配置没有权限自定义处理类
                    .exceptionHandling().accessDeniedHandler(userAuthAccessDeniedHandler)
                    .and()


                    // 开启跨域
                    .cors()
                    .and()
                    // 取消跨站请求伪造防护
                    .csrf().disable();

            // 基于Token不需要session
            http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            // 禁用缓存
            http.headers().cacheControl();
            // 添加JWT过滤器
            http.addFilter(new JwtAuthenticationTokenFilter(authenticationManager()));



        }


    }

    @Configuration
    @Order(2)
    class RequestConfigureAdapter extends WebSecurityConfigurerAdapter{


        /**
         * 配置登录验证逻辑
         */
        @Override
        protected void configure(AuthenticationManagerBuilder auth){
            //这里可启用我们自己的登陆验证逻辑
            auth.authenticationProvider(userAuthenticationProvider);
        }

        /**
         * 配置security的控制逻辑
         * @Author Sans
         * @CreateTime 2019/10/1 16:56
         * @Param  http 请求
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {


            http.authorizeRequests()
                    // 不进行权限验证的请求或资源(从配置文件中读取)
                    .antMatchers("/wjAppeal/pageQueryAppeal").permitAll()
                    .antMatchers(JwtConfig.antMatchers.split(",")).permitAll()
                    // 其他的需要登陆后才能访问
                    .anyRequest().authenticated()
                    .and()
                    // 配置未登录自定义处理类
                    .httpBasic().authenticationEntryPoint(userAuthenticationEntryPointHandler)
                    .and()
                    // 配置登录地址
                    .formLogin()
                    .loginProcessingUrl("/login/userLogin")
                    //登录表单form中用户名输入框input的name名，不修改的话默认是username, 我们只需要微信提供的code 就行
                    .usernameParameter("phone")
                    // 配置登录成功自定义处理类
                    .successHandler(userLoginSuccessHandler)
                    // 配置登录失败自定义处理类
                    .failureHandler(userLoginFailureHandler)
                    .and()
                    // 配置登出地址
                    .logout()
                    .logoutUrl("/login/userLogout")
                    // 配置用户登出自定义处理类
                    .logoutSuccessHandler(userLogoutSuccessHandler)
                    .and()
                    // 配置没有权限自定义处理类
                    .exceptionHandling().accessDeniedHandler(userAuthAccessDeniedHandler)
                    .and()


                    // start 配置短信登录
                    .formLogin()
                    .loginProcessingUrl("/login/smsLogin")
                    //登录表单form中用户名输入框input的name名，不修改的话默认是username, 我们只需要微信提供的code 就行
                    .usernameParameter("phone")
                    // 配置登录成功自定义处理类
                    .successHandler(userLoginSuccessHandler)
                    // 配置登录失败自定义处理类
                    .failureHandler(userLoginFailureHandler)
                    .and()
                    // 配置登出地址
                    .logout()
                    .logoutUrl("/login/userLogout")
                    // 配置用户登出自定义处理类
                    .logoutSuccessHandler(userLogoutSuccessHandler)
                    // 配置用户登出自定义处理类
                    .logoutSuccessHandler(userLogoutSuccessHandler)
                    .and()
                    // 配置没有权限自定义处理类
                    .exceptionHandling().accessDeniedHandler(userAuthAccessDeniedHandler)
                    // end 配置短信登录
                    .and()


                    // 开启跨域
                    .cors()
                    .and()
                    // 取消跨站请求伪造防护
                    .csrf().disable();

            // 基于Token不需要session
            http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            // 禁用缓存
            http.headers().cacheControl();
            // 添加JWT过滤器
            http.addFilter(new JwtAuthenticationTokenFilter(authenticationManager()));


        }



    }




}
